<template>
  <div v-if="visible" class="context-menu-overlay" @mousedown.stop @dblclick.stop.prevent>
    <div class="context-menu" @click.stop :style="menuStyle" @mousedown.stop @dblclick.stop.prevent>
      <div class="menu-header">
        <span class="menu-title">节点配置</span>
      </div>
      
      <div class="menu-content">
        <!-- 节点标签配置 - 结束节点不显示 -->
        <div class="menu-section" v-if="!isEndNode">
          <div class="section-title">节点标签</div>
          <div class="menu-items">
            <div class="config-item">
              <a-input
                v-model="nodeLabel"
                placeholder="请输入节点标签"
                style="width: 100%"
                size="small"
              />
            </div>
          </div>
        </div>

        <!-- 输入变量设置 - 结束节点不显示 -->
        <InputVariablesSection
          v-if="!isEndNode"
          :inputVariables="inputVariables"
          :inputVariableOptions="cascaderInputVariableOptions"
          :collapsed="inputVariablesCollapsed"
          :isStartNode="isStartNode"
          @toggle-collapsed="toggleInputVariables"
          @add-input-variable="addInputVariable"
          @remove-input-variable="removeInputVariable"
          @update:inputVariables="inputVariables = $event"
        />

        <!-- 通用设置 - 结束节点不显示 -->
        <GeneralSettingsSection
          v-if="!isEndNode"
          :nodeType="nodeType"
          :httpConfig="httpConfig"
          :scriptContent.sync="scriptContent"
          :timeout.sync="timeout"
          :collapsed="generalSettingsCollapsed"
          :availableVariables="availableVariables"
          :inputVariables="inputVariables"
          :judgeConditions="judgeConditions"
          :defaultNodeId="defaultNodeId"
          :endNodeId="endNodeId"
          :availableNodes="availableNodes"
          :directlyConnectedNodes="directlyConnectedNodes"
          :subsequentNodes="subsequentNodes"
          @toggle-collapsed="toggleGeneralSettings"
          @update:httpConfig="onHttpConfigUpdate"
          @add-judge-condition="addJudgeCondition"
          @remove-judge-condition="removeJudgeCondition"
          @update-judge-condition="updateJudgeCondition"
          @update:defaultNodeId="defaultNodeId = $event"
          @update:endNodeId="endNodeId = $event"
        />



        <!-- 输出变量设置 - 所有节点都显示 -->
        <OutputVariablesSection
          :outputVariables.sync="outputVariables"
          :collapsed="outputVariablesCollapsed"
          :nodeType="nodeType"
          :inputVariables="inputVariables"
          :availableVariables="availableVariables"
          @toggle-collapsed="toggleOutputVariables"
          @add-output-variable="addOutputVariable"
          @remove-output-variable="removeOutputVariable"
        />
      </div>

      <!-- 操作按钮 -->
      <div class="menu-footer">
        <a-button size="small" @click="handleCancel" style="margin-right: 8px;">
          取消
        </a-button>
        <a-button type="primary" size="small" @click="handleSave" :loading="saving">
          保存
        </a-button>
      </div>
    </div>
  </div>
</template>

<script>
import InputVariablesSection from './InputVariablesSection.vue'
import GeneralSettingsSection from './GeneralSettingsSection.vue'
import OutputVariablesSection from './OutputVariablesSection.vue'

export default {
  name: 'NodeConfigDialog',
  components: {
    InputVariablesSection,
    GeneralSettingsSection,
    OutputVariablesSection
  },
  props: {
    visible: {
      type: Boolean,
      default: false
    },
    nodeData: {
      type: Object,
      default: () => ({})
    },
    position: {
      type: Object,
      default: () => ({ x: 0, y: 0 })
    },
    graphManager: {
      type: Object,
      default: null
    },
    businessData: {
      type: Object,
      default: () => ({})
    }
  },
  computed: {
    menuStyle() {
      // 确保x和y是数字类型
      const x = Number(this.position.x) || 0
      const y = Number(this.position.y) || 0
      
      // 获取视口尺寸
      const viewportWidth = window.innerWidth
      const viewportHeight = window.innerHeight
      
      // 弹出层尺寸（估算）
      const dialogWidth = 450
      const dialogHeight = 600
      
      // 计算最佳位置
      let left = x + 20
      let top = y - 50
      
      // 检查右边界
      if (left + dialogWidth > viewportWidth) {
        left = x - dialogWidth - 20
      }
      
      // 检查下边界
      if (top + dialogHeight > viewportHeight) {
        top = viewportHeight - dialogHeight - 20
      }
      
      // 检查上边界
      if (top < 20) {
        top = 20
      }
      
      // 检查左边界
      if (left < 20) {
        left = 20
      }
      

      
      return {
        left: `${left}px`,
        top: `${top}px`
      }
    },
    
    inputVariableOptions() {
      if (!this.graphManager) return []

      const options = []
      const graph = this.graphManager.graph
      const nodes = graph.getNodes()
      const currentNodeId = this.nodeData.id
      const currentNode = nodes.find(n => n.id === currentNodeId)

      // 获取当前节点前面的节点
      const precedingNodes = this.getPrecedingNodes(currentNodeId)

      // 检查当前节点是否在组内
      const isCurrentNodeInGroup = this.isNodeInGroup(currentNode)

      // 获取所有候选节点：前面的节点 + 所有组节点
      const candidateNodes = [...precedingNodes]
      
      // 添加所有组节点
      nodes.forEach(node => {
        if (this.isGroupNode(node) && !candidateNodes.some(n => n.id === node.id)) {
          candidateNodes.push(node)
        }
      })

      candidateNodes.forEach((node, index) => {
        const nodeId = node.id
        const nodeLabel = node.attr('label/text') || '未命名节点'
        
        // 检查候选节点是否在组内
        const isCandidateNodeInGroup = this.isNodeInGroup(node)
        const isGroupNode = this.isGroupNode(node)
        
        // 过滤规则：
        // 1. 如果当前节点在组内，可以选择：
        //    - 同组内其他节点的输出变量
        //    - 组外节点的输出变量
        //    - 组节点的输出变量（整个组的输出）
        // 2. 如果当前节点在组外，可以选择：
        //    - 组外普通节点的输出变量
        //    - 组节点的输出变量（整个组的输出）
        //    - 不能选择组内单个节点的输出变量
        let shouldInclude = false
        
        if (isCurrentNodeInGroup) {
          // 当前节点在组内，可以选择同组内其他节点、组外节点或组节点
          const nodeData = node.getData()
          const isActuallyGroupNode = nodeData && (nodeData.type === 'group' || nodeData.type === 'group-flow')
          shouldInclude = isCandidateNodeInGroup || (!isCandidateNodeInGroup && !isActuallyGroupNode) || isActuallyGroupNode
        } else {
          // 当前节点在组外，可以选择组外节点或组节点，但不能选择组内单个节点
          // 注意：isGroupNode 为 true 可能是因为节点本身是组节点，也可能是因为父节点是组节点
          // 我们需要区分这两种情况
          const nodeData = node.getData()
          const isActuallyGroupNode = nodeData && (nodeData.type === 'group' || nodeData.type === 'group-flow')
          shouldInclude = (!isCandidateNodeInGroup && !isActuallyGroupNode) || isActuallyGroupNode
        }
        
        if (shouldInclude) {
          // 从Graph组件的businessData中获取节点的输出变量
          const bizData = this.businessData[nodeId] || {}
          const outputs = bizData.outputVariables || []

          if (outputs.length > 0) {
            const children = outputs.map(output => ({
              value: `${node.id}-${output.name}`,
              label: `${output.name}${output.type ? `(${output.type})` : ''}`,
              nodeId: node.id,
              nodeName: nodeLabel,
              outputName: output.name,
              outputType: output.type
            }))

            options.push({
              value: node.id,
              label: nodeLabel,
              children: children
            })
          }
        }
      })

      return options
    },
    
    cascaderInputVariableOptions() {
      // 仅对组节点做转换
      if (this.nodeData && (this.nodeData.type === 'group' || this.nodeData.type === 'group-flow')) {
        const options = this.nodeData.inputVariableOptions || []
        // 按 nodeName 分组
        const groupMap = {}
        options.forEach(opt => {
          const nodeName = opt.nodeName || '未知节点'
          if (!groupMap[nodeName]) {
            groupMap[nodeName] = []
          }
          groupMap[nodeName].push(opt)
        })
        return Object.entries(groupMap).map(([nodeName, children]) => ({
          value: nodeName,
          label: nodeName,
          children: children.map((child, idx) => ({
            ...child,
            value: child.outputName || `${nodeName}_${idx}`,
            label: (child.outputName || `未命名变量${idx+1}`) + (child.type ? `(${child.type})` : ''),
            nodeId: child.nodeId || child.sourceNodeId, // 确保有 nodeId 字段
            outputType: child.type // 确保有 outputType 字段
          }))
        }))
      }
      // 非组节点直接返回原始
      return this.inputVariableOptions || []
    },
    
    isStartEndNode() {
      return this.nodeData.type === 'start' || this.nodeData.type === 'end'
    },
    
    isEndNode() {
      return this.nodeData.type === 'end'
    },
    
    isStartNode() {
      return this.nodeData.type === 'start'
    },
    
    availableVariables() {
      // 获取所有节点的输出变量作为可用变量
      if (!this.graphManager) return []
      
      const variables = []
      const graph = this.graphManager.graph
      const nodes = graph.getNodes()
      
      nodes.forEach(node => {
        const nodeId = node.id
        const nodeLabel = node.attr('label/text') || '未命名节点'
        const nodeType = node.attr('type') || node.getData()?.type || 'unknown'
        const bizData = this.businessData[nodeId] || {}
        const outputs = bizData.outputVariables || []
        
        // 排除当前节点自己的输出变量
        if (nodeId !== this.nodeData.id) {
          outputs.forEach(output => {
            // 为结束节点提供下拉选择格式的选项
            if (this.isEndNode) {
              variables.push({
                value: `${nodeLabel} - ${output.name}`,
                label: `${nodeLabel} - ${output.name}${output.type ? `(${output.type})` : ''}`,
                name: output.name,
                type: output.type,
                sourceNode: nodeLabel,
                sourceNodeId: nodeId
              })
            } else {
              // 为其他节点提供原始格式
              variables.push({
                name: output.name,
                type: output.type,
                value: output.value,
                sourceNode: nodeLabel,
                sourceNodeId: nodeId
              })
            }
          })
        }
      })
      
      return variables
    },
    
    // 获取可用节点列表（用于判断设置中的目标节点选择）
    availableNodes() {
      if (!this.graphManager) return []
      
      const nodes = []
      const graph = this.graphManager.graph
      const allNodes = graph.getNodes()
      const currentNodeId = this.nodeData.id
      
      allNodes.forEach(node => {
        const nodeId = node.id
        const nodeType = node.getData()?.type || 'unknown'
        
        // 优先使用业务数据中的标签，如果没有则使用节点属性中的标签
        let nodeLabel = '未命名节点'
        if (this.businessData[nodeId] && this.businessData[nodeId].label) {
          nodeLabel = this.businessData[nodeId].label
        } else {
          nodeLabel = node.attr('label/text') || '未命名节点'
        }
        
        // 排除当前节点和开始节点
        if (nodeId !== currentNodeId && nodeType !== 'start') {
          nodes.push({
            id: nodeId,
            label: nodeLabel,
            type: nodeType
          })
        }
      })
      
      return nodes
    },
    
    // 获取直接连接的节点（用于判断条件的目标节点和else节点）
    directlyConnectedNodes() {
      if (!this.graphManager) return []
      
      const nodes = []
      const graph = this.graphManager.graph
      const currentNodeId = this.nodeData.id
      const allEdges = graph.getEdges()
      
      // 找到从当前节点出发的所有连线
      const outgoingEdges = allEdges.filter(edge => {
        const sourceId = edge.getSourceCellId()
        return sourceId === currentNodeId
      })
      
      // 获取直接连接的目标节点
      outgoingEdges.forEach(edge => {
        const targetId = edge.getTargetCellId()
        const targetNode = graph.getCellById(targetId)
        
        if (targetNode && targetNode.isNode()) {
          const nodeType = targetNode.getData()?.type || 'unknown'
          
          // 优先使用业务数据中的标签
          let nodeLabel = '未命名节点'
          if (this.businessData[targetId] && this.businessData[targetId].label) {
            nodeLabel = this.businessData[targetId].label
          } else {
            nodeLabel = targetNode.attr('label/text') || '未命名节点'
          }
          
          // 排除开始节点
          if (nodeType !== 'start') {
            nodes.push({
              id: targetId,
              label: nodeLabel,
              type: nodeType
            })
          }
        }
      })
      
      return nodes
    },
    
    // 获取后续所有节点（用于结束节点）
    subsequentNodes() {
      if (!this.graphManager) return []
      
      const nodes = []
      const graph = this.graphManager.graph
      const currentNodeId = this.nodeData.id
      const visited = new Set()
      const queue = [currentNodeId]
      
      // 使用BFS找到所有后续节点
      while (queue.length > 0) {
        const currentId = queue.shift()
        
        if (visited.has(currentId)) continue
        visited.add(currentId)
        
        // 获取当前节点的所有出边
        const allEdges = graph.getEdges()
        const outgoingEdges = allEdges.filter(edge => {
          const sourceId = edge.getSourceCellId()
          return sourceId === currentId
        })
        
        // 遍历所有出边
        outgoingEdges.forEach(edge => {
          const targetId = edge.getTargetCellId()
          const targetNode = graph.getCellById(targetId)
          
          if (targetNode && targetNode.isNode()) {
            const nodeType = targetNode.getData()?.type || 'unknown'
            
            // 优先使用业务数据中的标签
            let nodeLabel = '未命名节点'
            if (this.businessData[targetId] && this.businessData[targetId].label) {
              nodeLabel = this.businessData[targetId].label
            } else {
              nodeLabel = targetNode.attr('label/text') || '未命名节点'
            }
            
            // 排除开始节点和当前节点
            if (nodeType !== 'start' && targetId !== currentNodeId) {
              nodes.push({
                id: targetId,
                label: nodeLabel,
                type: nodeType
              })
              
              // 将目标节点加入队列，继续查找后续节点
              queue.push(targetId)
            }
          }
        })
      }
      
      return nodes
    }
  },
  data() {
    return {
      nodeLabel: '',
      nodeType: '',
      inputVariables: [],
      outputVariables: [],
      scriptContent: '',
      timeout: 30,
      httpConfig: {
        method: 'GET',
        url: '',
        headers: [],
        body: '',
        formData: [],
        activeTab: 'json',
        connectionTimeout: 15,
        readTimeout: 15,
        traverseObject: ''
      },
      saving: false,
      inputVariablesCollapsed: false,
      generalSettingsCollapsed: false,
      outputVariablesCollapsed: false,
      judgeSettingsCollapsed: false,
      judgeConditions: [],
      defaultNodeId: '',
      endNodeId: ''
    }
  },
  watch: {
    visible(newVal) {
      if (newVal) {
        this.initData()
      }
    },
    // 监听开始节点的输入变量变化，自动更新输出变量
    inputVariables: {
      handler(newVal) {
        if (this.isStartNode) {
          this.outputVariables = newVal.map(input => ({
            name: input.name,
            type: input.type,
            value: ''
          }))
        }
      },
      deep: true
    }
  },
  methods: {
    initData() {
      // 初始化数据
      this.nodeLabel = this.nodeData.label || '普通节点'
      this.nodeType = this.nodeData.type || ''
      this.inputVariables = [...(this.nodeData.inputVariables || [])]
      this.outputVariables = [...(this.nodeData.outputVariables || [])]
      this.scriptContent = this.nodeData.scriptContent || ''
      this.timeout = this.nodeData.timeout || 30
      this.httpConfig = {
        method: this.nodeData.httpConfig?.method || 'GET',
        url: this.nodeData.httpConfig?.url || '',
        headers: [...(this.nodeData.httpConfig?.headers || [])],
        body: this.nodeData.httpConfig?.body || '',
        formData: [...(this.nodeData.httpConfig?.formData || [])],
        activeTab: this.nodeData.httpConfig?.activeTab || 'json',
        connectionTimeout: this.nodeData.httpConfig?.connectionTimeout || 15,
        readTimeout: this.nodeData.httpConfig?.readTimeout || 15,
        traverseObject: this.nodeData.httpConfig?.traverseObject || this.nodeData.traverseObject || ''
      }
      
      // 如果是HTTP节点且没有输出变量，初始化固定的输出变量
      if (this.nodeType === 'HttpV1' && (!this.outputVariables || this.outputVariables.length === 0)) {
        this.outputVariables = [
          { name: 'response', type: 'object', value: '' },
          { name: 'connectionTime', type: 'number', value: '' },
          { name: 'readTime', type: 'number', value: '' }
        ]
      }
      
      // 如果是JSV1节点且没有脚本内容，设置默认脚本
      if (this.nodeType === 'JSV1' && !this.scriptContent) {
        this.scriptContent = `(input)=>{
    return {"outputVar1":"123"};
}`
      }
      
      // 初始化判断设置数据
      this.judgeConditions = [...(this.nodeData.judgeConditions || [])]
      this.defaultNodeId = this.nodeData.defaultNodeId || ''
      this.endNodeId = this.nodeData.endNodeId || ''
      
      // 如果没有判断条件，添加一个默认条件
      if (this.nodeType === 'judge' && this.judgeConditions.length === 0) {
        this.judgeConditions = [{
          script: '',
          targetNodeId: ''
        }]
      }
      
      // 使用$nextTick确保DOM更新
      this.$nextTick(() => {
        // DOM更新完成
      })
    },
    
    // 输入变量相关方法
    addInputVariable(variable) {
      this.inputVariables = [...this.inputVariables, variable]
      
      // 如果是开始节点，输出变量与输入变量保持一致
      if (this.isStartNode) {
        this.outputVariables = this.inputVariables.map(input => ({
          name: input.name,
          type: input.type,
          value: ''
        }))
      }
    },
    
    removeInputVariable(index) {
      this.inputVariables = this.inputVariables.filter((_, i) => i !== index)
      
      // 如果是开始节点，输出变量与输入变量保持一致
      if (this.isStartNode) {
        this.outputVariables = this.inputVariables.map(input => ({
          name: input.name,
          type: input.type,
          value: ''
        }))
      }
    },
    
    // 输出变量相关方法
    addOutputVariable(variable) {
      this.outputVariables = [...this.outputVariables, variable]
    },
    
    removeOutputVariable(index) {
      this.outputVariables = this.outputVariables.filter((_, i) => i !== index)
    },
    
    // 判断设置相关方法
    toggleJudgeSettings() {
      this.judgeSettingsCollapsed = !this.judgeSettingsCollapsed
    },
    
    addJudgeCondition(condition) {
      this.judgeConditions = [...this.judgeConditions, condition]
    },
    
    removeJudgeCondition(index) {
      this.judgeConditions = this.judgeConditions.filter((_, i) => i !== index)
    },
    
    updateJudgeCondition(index, updates) {
      this.judgeConditions = this.judgeConditions.map((condition, i) => {
        if (i === index) {
          return { ...condition, ...updates }
        }
        return condition
      })
    },
    
    // 验证判断设置
    validateJudgeSettings() {
      // 检查是否有判断条件
      if (!this.judgeConditions || this.judgeConditions.length === 0) {
        return { isValid: false, message: '请至少添加一个判断条件' }
      }
      
      // 检查每个判断条件
      for (let i = 0; i < this.judgeConditions.length; i++) {
        const condition = this.judgeConditions[i]
        
        // 检查脚本是否为空
        if (!condition.script || !condition.script.trim()) {
          return { isValid: false, message: `第${i + 1}个判断条件的脚本不能为空` }
        }
        
        // 检查目标节点是否已选择
        if (!condition.targetNodeId) {
          return { isValid: false, message: `第${i + 1}个判断条件的目标节点不能为空` }
        }
      }
      
      // 检查默认节点是否已选择
      if (!this.defaultNodeId) {
        return { isValid: false, message: '请选择默认节点' }
      }
      
      // 检查结束节点是否已选择
      if (!this.endNodeId) {
        return { isValid: false, message: '请选择结束节点' }
      }
      
      // 检查结束节点不能是目标节点或默认节点
      const allTargetNodeIds = this.judgeConditions.map(condition => condition.targetNodeId)
      const forbiddenNodeIds = [...allTargetNodeIds, this.defaultNodeId]
      
      if (forbiddenNodeIds.includes(this.endNodeId)) {
        return { isValid: false, message: '结束节点不能是目标节点或else节点' }
      }
      
      return { isValid: true, message: '' }
    },
    

    
    // 折叠/展开相关方法
    toggleInputVariables() {
      this.inputVariablesCollapsed = !this.inputVariablesCollapsed
    },
    
    toggleGeneralSettings() {
      this.generalSettingsCollapsed = !this.generalSettingsCollapsed
    },
    
    toggleOutputVariables() {
      this.outputVariablesCollapsed = !this.outputVariablesCollapsed
    },
    
    handleCancel() {
      this.$emit('cancel')
    },
    
    handleSave() {
      // 验证数据
      if (!this.isEndNode && !this.nodeLabel.trim()) {
        this.$message.error('请输入节点标签')
        return
      }
      

      
      // 验证输入变量是否与前面节点的输出变量对应
      if (!this.isEndNode && this.inputVariables.length > 0) {
        const validationResult = this.validateInputVariables()
        if (!validationResult.isValid) {
          this.$message.error(validationResult.message)
          return
        }
      }
      
      // 验证HTTP配置中的变量标签是否与输入变量对应
      if (!this.isEndNode && this.nodeType === 'HttpV1') {
        const httpValidationResult = this.validateHttpConfigVariables()
        if (!httpValidationResult.isValid) {
          this.$message.error(httpValidationResult.message)
          return
        }
      }
      
      // 验证脚本内容中的变量标签是否与输入变量对应
      if (!this.isEndNode && this.scriptContent) {
        const scriptValidationResult = this.validateScriptContentVariables()
        if (!scriptValidationResult.isValid) {
          this.$message.error(scriptValidationResult.message)
          return
        }
      }
      
      // 验证判断设置
      if (this.nodeType === 'judge') {
        const judgeValidationResult = this.validateJudgeSettings()
        if (!judgeValidationResult.isValid) {
          this.$message.error(judgeValidationResult.message)
          return
        }
      }
      
      this.saving = true
      
      // 模拟保存
      setTimeout(() => {
        let configData = {}
        
        if (this.isEndNode) {
          // 结束节点只保存输出变量
          configData = {
            label: this.nodeData.label, // 保持原有标签
            type: this.nodeData.type, // 保持原有类型
            outputVariables: this.outputVariables
          }
        } else {
          // 普通节点和开始节点保存所有配置
          configData = {
            label: this.nodeLabel.trim(),
            type: this.nodeType,
            inputVariables: this.inputVariables,
            outputVariables: this.outputVariables,
            scriptContent: this.scriptContent,
            timeout: this.timeout,
            httpConfig: this.httpConfig
          }
          
          // 如果是组节点，添加遍历对象
          if (this.nodeType === 'group') {
            configData.traverseObject = this.httpConfig.traverseObject
          }
          
          // 如果是判断节点，添加判断设置
          if (this.nodeType === 'judge') {
            configData.judgeConditions = this.judgeConditions
            configData.defaultNodeId = this.defaultNodeId
            configData.endNodeId = this.endNodeId
          }
          
          // 如果是开始节点，确保输出变量与输入变量保持一致
          if (this.isStartNode) {
            configData.outputVariables = this.inputVariables.map(input => ({
              name: input.name,
              type: input.type,
              value: ''
            }))
          }
        }
        
        this.$emit('save', configData)
        this.saving = false
      }, 500)
    },
    
    validateInputVariables() {
      if (!this.graphManager) {
        return { isValid: false, message: '图形管理器未初始化' }
      }
      
      // 如果是开始节点，不需要验证输入变量（因为它们是手动输入的）
      if (this.isStartNode) {
        return { isValid: true, message: '' }
      }
      
      const graph = this.graphManager.graph
      const nodes = graph.getNodes()
      
      for (const inputVar of this.inputVariables) {
        // 查找对应的源节点
        const sourceNode = nodes.find(node => node.id === inputVar.nodeId)
        if (!sourceNode) {
          return { 
            isValid: false, 
            message: `找不到源节点: ${inputVar.nodeName}` 
          }
        }
        
        // 获取源节点的输出变量
        const bizData = this.businessData[inputVar.nodeId] || {}
        const outputs = bizData.outputVariables || []
        
        // 查找对应的输出变量
        const outputVar = outputs.find(output => output.name === inputVar.outputName)
        if (!outputVar) {
          return { 
            isValid: false, 
            message: `节点 ${inputVar.nodeName} 没有输出变量: ${inputVar.outputName}` 
          }
        }
        
        // 检查变量类型是否匹配
        if (inputVar.type && outputVar.type && inputVar.type !== outputVar.type) {
          return { 
            isValid: false, 
            message: `变量类型不匹配: ${inputVar.nodeName} - ${inputVar.outputName} (期望: ${inputVar.type}, 实际: ${outputVar.type})` 
          }
        }
      }
      
      return { isValid: true, message: '' }
    },
    
    validateHttpConfigVariables() {
      if (!this.httpConfig) {
        return { isValid: true, message: '' }
      }
      
      // 从已选择的输入变量中提取变量名和类型映射
      const inputVarMap = new Map()
      this.inputVariables.forEach(inputVar => {
        // 开始节点的输入变量使用name属性，普通节点使用outputName属性
        const variableName = this.isStartNode ? inputVar.name : inputVar.outputName
        inputVarMap.set(variableName, {
          nodeName: inputVar.nodeName || '开始节点',
          type: inputVar.type
        })
      })
      
      // 检查URL中的变量标签
      if (this.httpConfig.url) {
        const urlValidation = this.validateVariableTags(this.httpConfig.url, inputVarMap, 'URL')
        if (!urlValidation.isValid) {
          return urlValidation
        }
      }
      
      // 检查Headers中的变量标签
      if (this.httpConfig.headers && this.httpConfig.headers.length > 0) {
        for (const header of this.httpConfig.headers) {
          if (header.value) {
            const headerValidation = this.validateVariableTags(header.value, inputVarMap, `请求头 ${header.name}`)
            if (!headerValidation.isValid) {
              return headerValidation
            }
          }
        }
      }
      
      // 检查Body中的变量标签
      if (this.httpConfig.body) {
        const bodyValidation = this.validateVariableTags(this.httpConfig.body, inputVarMap, '请求体')
        if (!bodyValidation.isValid) {
          return bodyValidation
        }
      }
      
      // 检查Form Data中的变量标签
      if (this.httpConfig.formData && this.httpConfig.formData.length > 0) {
        for (const field of this.httpConfig.formData) {
          if (field.value) {
            const fieldValidation = this.validateVariableTags(field.value, inputVarMap, `表单字段 ${field.name}`)
            if (!fieldValidation.isValid) {
              return fieldValidation
            }
          }
        }
      }
      
      return { isValid: true, message: '' }
    },
    
    validateScriptContentVariables() {
      if (!this.scriptContent) {
        return { isValid: true, message: '' }
      }

      // 从已选择的输入变量中提取变量名和类型映射
      const inputVarMap = new Map()
      this.inputVariables.forEach(inputVar => {
        // 开始节点的输入变量使用name属性，普通节点使用outputName属性
        const variableName = this.isStartNode ? inputVar.name : inputVar.outputName
        inputVarMap.set(variableName, {
          nodeName: inputVar.nodeName || '开始节点',
          type: inputVar.type
        })
      })

      // 使用正则表达式匹配变量标签
      const variableTagRegex = /<span class="variable-tag"[^>]*data-variable="([^"]*)"[^>]*>([^<]*)<\/span>/g
      let match
      
      while ((match = variableTagRegex.exec(this.scriptContent)) !== null) {
        const variableName = match[1]
        const displayText = match[2]
        
        // 检查变量是否在已选择的输入变量中
        if (!inputVarMap.has(variableName)) {
          return {
            isValid: false,
            message: `脚本内容中使用了未选择的输入变量: ${variableName}`
          }
        }
        
        // 检查显示文本是否匹配（可选验证）
        const expectedDisplayText = this.getExpectedDisplayText(variableName, inputVarMap.get(variableName))
        if (displayText !== expectedDisplayText) {
          return {
            isValid: false,
            message: `脚本内容中变量标签显示文本不匹配: ${variableName} (期望: ${expectedDisplayText}, 实际: ${displayText})`
          }
        }
      }
      
      return { isValid: true, message: '' }
    },
    
    validateVariableTags(content, inputVarMap, location) {
      // 使用正则表达式匹配变量标签
      const variableTagRegex = /<span class="variable-tag"[^>]*data-variable="([^"]*)"[^>]*>([^<]*)<\/span>/g
      let match
      
      while ((match = variableTagRegex.exec(content)) !== null) {
        const variableName = match[1]
        const displayText = match[2]
        
        // 检查变量是否在已选择的输入变量中
        if (!inputVarMap.has(variableName)) {
          return {
            isValid: false,
            message: `${location}中使用了未选择的输入变量: ${variableName}`
          }
        }
        
        // 检查显示文本是否匹配（可选验证）
        const expectedDisplayText = this.getExpectedDisplayText(variableName, inputVarMap.get(variableName))
        if (displayText !== expectedDisplayText) {
          return {
            isValid: false,
            message: `${location}中变量标签显示文本不匹配: ${variableName} (期望: ${expectedDisplayText}, 实际: ${displayText})`
          }
        }
      }
      
      return { isValid: true, message: '' }
    },
    
    getExpectedDisplayText(variableName, inputVar) {
      const typeText = inputVar.type ? `(${inputVar.type})` : ''
      return `${inputVar.nodeName} - ${variableName}${typeText}`
    },
    
    onHttpConfigUpdate(event) {

      // 确保保持所有现有属性，只更新传入的属性
      this.httpConfig = {
        ...this.httpConfig,
        ...event
      }
    },

    // 获取当前节点前面的节点
    getPrecedingNodes(currentNodeId) {
      if (!this.graphManager) return []
      const graph = this.graphManager.graph
      const nodes = graph.getNodes()
      const edges = graph.getEdges()
      
      // 构建邻接表
      const adjacencyList = new Map()
      nodes.forEach(node => {
        adjacencyList.set(node.id, [])
      })
      
      // 添加边
      edges.forEach(edge => {
        const sourceId = edge.getSourceCellId()
        const targetId = edge.getTargetCellId()
        if (adjacencyList.has(sourceId)) {
          adjacencyList.get(sourceId).push(targetId)
        }
      })
      
      // 使用拓扑排序找到当前节点的所有前驱节点
      const visited = new Set()
      const precedingNodes = []
      
      const dfs = (nodeId, path = []) => {
        if (path.includes(nodeId)) {
          return // 避免循环依赖
        }
        
        if (nodeId === currentNodeId) {
          // 找到当前节点，将路径中的所有节点添加到前驱节点列表
          path.forEach(id => {
            if (!visited.has(id)) {
              visited.add(id)
              const node = nodes.find(n => n.id === id)
              if (node) {
                precedingNodes.push(node)
              }
            }
          })
          return
        }
        
        const neighbors = adjacencyList.get(nodeId) || []
        for (const neighborId of neighbors) {
          dfs(neighborId, [...path, nodeId])
        }
      }
      
      // 从所有没有入边的节点开始DFS
      const inDegree = new Map()
      nodes.forEach(node => {
        inDegree.set(node.id, 0)
      })
      
      edges.forEach(edge => {
        const targetId = edge.getTargetCellId()
        inDegree.set(targetId, (inDegree.get(targetId) || 0) + 1)
      })
      
      const startNodes = nodes.filter(node => inDegree.get(node.id) === 0)
      
      startNodes.forEach(node => {
        dfs(node.id)
      })
      
      // 如果没有找到前驱节点，返回所有在当前节点之前的节点（按创建顺序）
      if (precedingNodes.length === 0) {
        for (const node of nodes) {
          if (node.id === currentNodeId) {
            break
          }
          precedingNodes.push(node)
        }
      }
      
      return precedingNodes
    },

    // 辅助方法：检查节点是否在组内
    isNodeInGroup(node) {
      if (!node) return false
      
      // 检查节点是否有父节点（组节点）
      const parent = node.getParent()
      
      if (parent && parent.isNode()) {
        // 检查父节点是否是组节点
        const parentData = parent.getData()
        const isGroup = parentData && parentData.type === 'group'
        return isGroup
      }
      
      return false
    },

    // 辅助方法：检查节点是否是组节点
    isGroupNode(node) {
      if (!node) return false
      
      // 检查节点本身是否是组节点
      const nodeData = node.getData()
      const isNodeGroup = nodeData && (nodeData.type === 'group' || nodeData.type === 'group-flow')
      
      // 检查节点的父节点是否是组节点
      const parent = node.getParent()
      const isParentGroup = parent && parent.isNode() && parent.getData() && 
                           (parent.getData().type === 'group' || parent.getData().type === 'group-flow')
      
      return isNodeGroup || isParentGroup
    }
  }
}
</script>

<style scoped>
.context-menu-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 9999;
}

.context-menu {
  position: fixed;
  background: white;
  border-radius: 6px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.1);
  min-width: 400px;
  max-width: 500px;
  max-height: calc(100vh - 40px);
  overflow: hidden;
  border: 1px solid #e8e8e8;
  z-index: 10000;
  display: flex;
  flex-direction: column;
  user-select: none;
}
.context-menu input,
.context-menu textarea,
.context-menu [contenteditable] {
  user-select: text;
}

/* 确保下拉框显示在最上层 */
.context-menu .ant-select-dropdown,
.context-menu .ant-cascader-menus,
.context-menu .ant-tabs-dropdown {
  z-index: 10001 !important;
}

/* 全局确保下拉框显示在最上层 */
:global(.ant-select-dropdown) {
  z-index: 10001 !important;
}

:global(.ant-cascader-menus) {
  z-index: 10001 !important;
}

:global(.ant-tabs-dropdown) {
  z-index: 10001 !important;
}

.menu-header {
  padding: 8px 12px;
  background: #fafafa;
  border-bottom: 1px solid #e8e8e8;
}

.menu-title {
  font-size: 12px;
  color: #666;
  font-weight: 500;
}

.menu-content {
  flex: 1;
  overflow-y: auto;
  max-height: 400px;
  min-height: 200px;
  /* 确保滚动条显示 */
  overflow-x: hidden;
  /* 强制显示滚动条 */
  scrollbar-width: thin;
  scrollbar-color: #c1c1c1 #f1f1f1;
}

/* Webkit浏览器的滚动条样式 */
.menu-content::-webkit-scrollbar {
  width: 6px;
}

.menu-content::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 3px;
}

.menu-content::-webkit-scrollbar-thumb {
  background: #c1c1c1;
  border-radius: 3px;
}

.menu-content::-webkit-scrollbar-thumb:hover {
  background: #a8a8a8;
}

.menu-section {
  padding: 4px 0;
}

.menu-section:not(:last-child) {
  border-bottom: 1px solid #f0f0f0;
}

.section-title {
  padding: 4px 12px;
  font-size: 11px;
  color: #999;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.menu-items {
  padding: 8px 12px;
}

.config-item {
  margin-bottom: 8px;
}

.config-item:last-child {
  margin-bottom: 0;
}

.config-label {
  display: block;
  font-size: 11px;
  color: #666;
  margin-bottom: 4px;
  font-weight: 500;
}

.menu-footer {
  padding: 8px 12px;
  text-align: right;
  border-top: 1px solid #f0f0f0;
  background: #fafafa;
}

.menu-footer .ant-btn {
  margin-left: 4px;
}
</style> 